package com.celesea.auth.dept.service;

import com.celesea.auth.dept.dao.DeptDao;
import com.celesea.auth.dept.entity.Dept;
import com.celesea.auth.dept.entity.DeptUser;
import com.celesea.auth.dept.vo.DeptTreeVo;
import com.celesea.auth.dept.vo.DeptVo;
import com.celesea.auth.position.service.PositionService;
import com.celesea.auth.role.entity.RoleCode;
import com.celesea.auth.role.service.RoleUserService;
import com.celesea.auth.user.dao.UserDao;
import com.celesea.auth.user.entity.User;
import com.celesea.auth.user.service.UserService;
import com.celesea.framework.entity.BusEntity;
import com.celesea.framework.service.AbstractBaseService;
import com.celesea.framework.util.CollectionKit;
import com.celesea.framework.util.Const;
import com.celesea.framework.util.EnvUtil;
import com.celesea.framework.util.StringKit;
import com.celesea.framework.util.tree.TreeUtil;
import com.celesea.framework.vo.DictionaryVo;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author JackYuan
 * @create 2017-10-28 21:39
 */
@Service
public class DeptServiceImpl extends AbstractBaseService<Dept> implements DeptService {

    public static final String COMPANY_FLAG = "companyFlag";
    public static final String PARENT_ID = "parentId";
    @Autowired
    private DeptDao deptDao;

    @Autowired
    private DeptUserService deptUserService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleUserService roleUserService;

    @Autowired
    private PositionService positionService;

    @Override
    public List<DeptTreeVo> selectNodes(String parentId) {
        Example example = new Example(Dept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId()).
                andEqualTo(BusEntity.DELETE_FLAG, Const.Bool.TRUE);
        if (StringKit.isEmpty(parentId)) {
            criteria.andEqualTo("id", EnvUtil.getCompany());
        } else {
            criteria.andEqualTo("parentId", parentId);
        }

        List<Dept> depts = deptDao.selectByExample(example);

        return depts.stream().map(item -> new DeptTreeVo(item)).collect(Collectors.toList());
    }

    @Override
    public List<DeptTreeVo> selectDepts() {
        Dept root = this.selectById(EnvUtil.getCompany());
        List<DeptTreeVo> trees = Lists.newArrayList(new DeptTreeVo(root));
        fillDeptChild(trees);
        return trees;
    }

    private void fillDeptChild(List<DeptTreeVo> nodes) {
        if (CollectionKit.isEmpty(nodes)) {
            return;
        }
        nodes.forEach(item -> {
            List<DeptTreeVo> childs = this.selectNodes(item.getId());
            fillDeptChild(childs);
            item.setChildren(childs);
            item.setLeaf(CollectionKit.isEmpty(childs) ? Const.Bool.TRUE : Const.Bool.FALSE);
        });
    }

    private List<Dept> selectByCompany() {
        Example example = new Example(Dept.class);
        Example.Criteria criteria = example.createCriteria();

        criteria.andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId())
                .andEqualTo(BusEntity.DELETE_FLAG, Const.Bool.TRUE)
                .andEqualTo("company", EnvUtil.getCompany());
        // TODO 父子公司问题
        example.orderBy("parentId").asc().orderBy("sort").asc();

        List<Dept> depts = deptDao.selectByExample(example);
        return depts;
    }

    @Override
    public String selectRootId(String tenantId) {
        return deptDao.selectRootId(tenantId);
    }

    @Override
    public void updateFixCompany(String companyId) {
        Dept entity = super.selectById(companyId);
        Assert.notNull(entity, "公司信息不存在！");
        Assert.isTrue(Const.Bool.isTrue(entity.getCompanyFlag()), "只能以公司为起点修复！");

        List<String> childIds = getAllChildDept(companyId);
        childIds.add(companyId);// include self
        if (CollectionKit.isNotEmpty(childIds)) {
            fixChildrenOfCompany(companyId, childIds);
            // 修复用户的所属公司
            userService.updateFixCompany(companyId, childIds);
            // 岗位
            positionService.updateFixCompany(companyId, childIds);
        }
    }

    private List<String> getAllChildDept(String id) {
        List<String> tempIds = Lists.newArrayList();
        List<String> childIds = findChildDept(id);
        if (CollectionKit.isNotEmpty(childIds)) {
            childIds.forEach(childId -> {
                tempIds.addAll(getAllChildDept(childId));
            });
        }
        tempIds.addAll(childIds);
        return tempIds;
    }

    /**
     * 查询出非公司的子节点
     */
    private List<String> findChildDept(String id) {

        Example example = new Example(Dept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId())
                .andEqualTo(COMPANY_FLAG, Const.Bool.FALSE)
                .andEqualTo(PARENT_ID, id);

        List<Dept> depts = deptDao.selectByExample(example);

        List<String> childs = Lists.newArrayList();
        depts.forEach(item -> childs.add(item.getId()));
        return childs;
    }

    /**
     * 修复子部门的公司字段
     */
    private void fixChildrenOfCompany(String id, List<String> childIds) {
        Example example = new Example(Dept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId())
                .andEqualTo(COMPANY_FLAG, Const.Bool.FALSE)
                .andIn(PARENT_ID, childIds);
        // fix child dept
        Dept entity = new Dept();
        entity.setCompany(id);
        deptDao.updateByExampleSelective(entity, example);
    }

    /**
     * 构建全量树
     *
     * @return
     */
    public List<DeptTreeVo> selectFullTree() {
        Example example = new Example(Dept.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo(BusEntity.TALENT_ID, EnvUtil.getTenantId())
                .andEqualTo(BusEntity.DELETE_FLAG, Const.Bool.TRUE);
        example.orderBy("parentId").asc();
        List<Dept> depts = deptDao.selectByExample(example);
        List<DeptTreeVo> trees = depts.stream().map(item -> new DeptTreeVo(item))
                .collect(Collectors.toList());
        return TreeUtil.build2Tree(trees, null);
    }

    @Override
    public List<String> selectChilds(String id) {
        List<DeptTreeVo> trees = selectFullTree();
        return TreeUtil.treeChildIds(trees, id);
    }

    @Override
    public List<String> selectParents(String id) {
        List<DeptTreeVo> trees = selectFullTree();
        return TreeUtil.treeParentIds(trees, id);
    }

    @Override
    public DeptVo insert(DeptVo deptVo) {
        Assert.isTrue(super.checkUnique(deptVo.toUnique()), "部门编码重复");
        Dept entity = deptVo.toEntity();
        Assert.isTrue(entity.getParentId() != null, "上级不能为空！");
        checkAdmin(entity);
        processCompanyByParent(entity);
        Dept dept = super.insert(entity);
        entity.setId(dept.getId());
        deptUserService.insertByDept(deptVo);
        return deptVo;
    }

    private void processCompanyByParent(Dept entity) {
        if (Const.Bool.isTrue(entity.getCompanyFlag())) {
            // root  or child company
            if (StringKit.isEmpty(entity.getId())) {
                super.generatPk(entity);
            }
            entity.setCompany(entity.getId());
        } else {
            // dept
            Dept parent = super.selectById(entity.getParentId());
            Assert.notNull(parent, "所属父级不存在！");
            Assert.notNull(parent.getCompany(), "所属父级公司归属信息不正确！");
            entity.setCompany(parent.getCompany());
        }
    }

    private void checkAdmin(Dept entity) {
        entity.checkAdmin();
        // 检查新建公司的权限
        if (StringKit.isNotEmpty(entity.getId())) {
            // 检查数据库对象是否为公司
            Dept db = super.selectById(entity.getId());
            if (Const.Bool.isTrue(db.getCompanyFlag())) {
                boolean reuiredAdminSystem = EnvUtil.hasAnyRoles(RoleCode.ADMIN_SYSTEM);
                Assert.isTrue(reuiredAdminSystem, "您没有权限执行当前操作！");
            }
        }
        boolean isRealRoot = entity.getParentId() == null;
        if (isRealRoot) {
            super.generatPk(entity);
            entity.setCompany(entity.getId());
        }
    }

    @Override
    public DeptVo update(DeptVo deptVo) {
        Assert.isTrue(super.checkUnique(deptVo.toUnique()), "部门编码重复");
        Dept entity = deptVo.toEntity();
        checkRoot(entity);
        checkAdmin(entity);
        processCompanyByParent(entity);
        super.update(entity);
        deptUserService.deleteByDept(entity.getId());
        deptUserService.insertByDept(deptVo);

        boolean isCompany = Const.Bool.isTrue(entity.getCompanyFlag());
        if (isCompany) {
            this.updateFixCompany(entity.getId());
        }
        return deptVo;
    }

    private void checkRoot(Dept entity) {
        boolean isRoot = entity.isCurrentRoot();
        boolean isCompany = Const.Bool.isTrue(entity.getCompanyFlag());
        if (isRoot) {
            Assert.isTrue(isCompany, "根节点的类型必须为公司");
            // 当前是root不可以更新上级
            if (StringKit.isEmpty(entity.getParentId())) {
                entity.setParentId(null);
                entity.setParentName(null);
            } else {
                Dept parent = super.selectById(entity.getParentId());
                entity.setParentId(parent.getId());
                entity.setParentName(parent.getName());
            }
        }
    }

    @Override
    public DeptVo buildById(String parentId) {
        DeptVo deptVo = new DeptVo();
        if (StringKit.isNotEmpty(parentId)) {
            Dept parent = super.selectById(parentId);
            deptVo.setParent(new DictionaryVo(parent.getId(), parent.getName()));
        }
        deptVo.setCompanyFlag(Const.Bool.FALSE);
        deptVo.setAdmins(roleUserService.findByRoleCode(RoleCode.ADMIN_BUS));

        return deptVo;
    }

    @Override
    public DeptVo selectById(String id) {
        Dept dept = super.selectById(id);
        DeptVo deptVo = new DeptVo(dept);
        if (StringKit.isNotEmpty(dept.getParentId())) {
            Dept parent = super.selectById(dept.getParentId());
            deptVo.setParent(new DictionaryVo(parent.getId(), parent.getName()));
        }

        if (Const.Bool.isTrue(dept.getCompanyFlag())) {
            if (StringKit.isNotEmpty(dept.getAdminId())) {
                User admin = userDao.selectByPrimaryKey(dept.getAdminId());
                deptVo.setAdmin(new DictionaryVo(admin.getId(), admin.getName()));
            }
        }
        deptVo.setAdmins(roleUserService.findByRoleCode(RoleCode.ADMIN_BUS));

        List<DeptUser> users = deptUserService.findByDept(id);
        deptVo.fillDeptMembers(users);

        return deptVo;
    }
}
